import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class UriFetcher {
	
	private static HttpClient httpClient;
	
	private static Logger logger = LoggerFactory
	.getLogger(UriFetcher.class);
	
	private UriFetcher() {}
	
	public static void init() {
		HttpParams params = new BasicHttpParams();
		/*
		 * ConnPerRoute connPerRoute = new ConnPerRouteBean(2);
		 * ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
		 * ConnManagerParams.setMaxTotalConnections(params, 10);
		 * ConnManagerParams.setTimeout(params, 20 * 1000); // 20 seconds
		 * HttpConnectionParams.setConnectionTimeout(params, 20000);
		 * HttpConnectionParams.setSoTimeout(params, 20000);
		 * HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		 */
		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory
				.getSocketFactory(), 80));

		// Create an HttpClient with the ThreadSafeClientConnManager.
		// This connection manager must be used if more than one thread will
		// be using the HttpClient.
		ClientConnectionManager cm = new ThreadSafeClientConnManager(params,
				schemeRegistry);
		httpClient = new DefaultHttpClient(cm, params);
	}
	
	public static String encodeSpaces(String uri) {
		return uri.replaceAll(" ", "%20");
	}
	
	public static String toFileName(String uri) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < uri.length(); i++) {
			Character ch = uri.charAt(i);
			if (Character.isLetterOrDigit(ch)) {
				sb.append(ch);
			}
		}
		sb.append(".html");
		return sb.toString();
	}

	
	public static void fetchToDisk(String uri, int count) {
		if (httpClient == null) {
			logger.debug("Initializing http client...");
			init();
		}
		
		logger.debug(String.format("%d: Calling %s", count, uri));
		BufferedOutputStream out = null;
		BufferedInputStream in = null;
		try {
			HttpGet httpget = new HttpGet(encodeSpaces(uri));
			HttpResponse response;
			File outFile = new File(toFileName(uri));
			out = new BufferedOutputStream(new FileOutputStream(outFile));
			response = httpClient.execute(httpget);
			in = new BufferedInputStream(response.getEntity().getContent());
			while (true) {
				int data = in.read();
				if (data == -1) {
					break;
				}
				out.write(data);
			}
		} catch (ParseException e) {
			logger.warn(String.format("Error fetching %s", uri), e);
		} catch (ClientProtocolException e) {
			logger.warn(String.format("Error fetching %s", uri), e);
		} catch (IOException e) {
			logger.warn(String.format("Error fetching %s", uri), e);
		} catch (RuntimeException e) {
			logger.warn(String.format("Error fetching %s", uri), e);
		} finally {
			try {
				if (in != null)
					in.close();
				if (out != null)
					out.close();
			} catch (IOException e1) {
				// ignore
			}
		}
	}

}
